package br.mikhas.util;

import java.util.Collection;

/**
 * Assertion utilities
 * 
 * @author Mikhail Domanoski
 * 
 */
public final class Assert {
	// Prevent instantiation
	private Assert() {

	}

	/**
	 * Assert that the object is not null
	 * 
	 * @param object
	 *            the object to check
	 * @param message
	 *            the exception message if the assertion fails
	 */
	public static void notNull(Object object) {
		if (object == null) {
			throw new AssertionException("Argument must not be null");
		}
	}

	/**
	 * Assert that both objects are equal
	 * 
	 * @param expected
	 *            first object to check
	 * @param acctual
	 *            second object to check
	 */
	public static void equals(Object expected, Object acctual) {
		if (expected != null && acctual != null) {
			if (expected != acctual && !expected.equals(acctual)) {
				throwEquals(expected, acctual);
			}
		}
	}

	/**
	 * Assert that both integer numbers are equals
	 * 
	 * @param expected
	 *            The expected value
	 * @param acctual
	 *            The recieved value
	 */
	public static void equals(int expected, int acctual) {
		if (expected != acctual) {
			throwEquals(expected, acctual);
		}
	}

	/**
	 * Assert that both decimal numbers are equals
	 * 
	 * @param expected
	 *            The expected value
	 * @param acctual
	 *            The recieved value
	 */
	public static void equals(double expected, double acctual) {
		if (expected != acctual) {
			throwEquals(expected, acctual);
		}
	}

	/**
	 * Asserts that a boolean expression is true
	 * 
	 * @param expression
	 *            The expression to check that is true
	 */
	public static void isTrue(boolean expression) {
		if (!expression) {
			throw new AssertionException("Expression value must be true.");
		}
	}

	/**
	 * Asserts that a string is not empty
	 * 
	 * @param string
	 *            The string to be checked
	 */
	public static void notEmpty(String string) {
		notNull(string);
		if (string.isEmpty()) {
			throw new AssertionException("String must not be empty");
		}
	}

	/**
	 * Asserts that a collection is not empty
	 * 
	 * @param collection
	 *            The collection to be checked
	 */
	public static void notEmpty(Collection<?> collection) {
		notNull(collection);
		if (collection.isEmpty()) {
			throw new AssertionException("Collection must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(Object[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(int[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(double[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(long[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(float[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(char[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(byte[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Asserts that an array is not empty
	 * 
	 * @param array
	 *            The array to be checked
	 */
	public static void notEmpty(boolean[] array) {
		notNull(array);
		if (array.length < 1) {
			throw new AssertionException("Array must not be empty");
		}
	}

	/**
	 * Throw {@link AssertionException} for equality assertions
	 * 
	 * @param expected
	 *            The expected value
	 * @param acctual
	 *            The recieced value
	 */
	private static void throwEquals(Object expected, Object acctual) {
		throw new AssertionException(
				"Both argument should be equals: was expected [" + expected
						+ "] but [" + acctual + "] was recieved.");
	}

	/**
	 * Assertion exception to be thrown when and assertion error occurs
	 * 
	 * @author Mikhail Domanoski
	 * 
	 */
	public static class AssertionException extends RuntimeException {

		private static final long serialVersionUID = -80028044659080927L;

		public AssertionException() {

		}

		public AssertionException(String message) {
			super(message);
		}

		public AssertionException(Throwable cause) {
			super(cause);
		}

		public AssertionException(String message, Throwable cause) {
			super(message, cause);
		}

	}
}
